// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Repository/HDF5/Input/Dynamic/DynamicSummaryRepository.h"

#include "DBManager/IRepository/Input/Dynamic/IDynamicSummaryRepository.h"
#include "DBManager/Repository/HDF5/Base/HDF5RepositoryMacro.h"
#include "DBManager/Repository/HDF5/Base/SingleRepositoryBase.h"

HDF5_REG_REPOSITORY (DynamicSummaryRepository)

using namespace SG::DBManager::HDF5;

using namespace SG::DBManager;
using namespace SG::DataStructure::FEM;
DynamicSummaryRepository::DynamicSummaryRepository (HDF5Database& database)
    : MainlyRepositoryBase<MultiSummaryInfo<SG::DataStructure::FEM::DynamicType>> (database)
{}

void DynamicSummaryRepository::InitialDatasetInfo ()
{
    RegisterTableInfo<SG::DataStructure::Common::Id> ("/OWN/INDEX/INPUT/DYNAMIC/SUMMARY", IndexDataset);
    RegisterTableInfo<SummaryIDENTITY> ("/OWN/INPUT/DYNAMIC/SUMMARY", MainDataset);
    RegisterTableInfo<SG::DataStructure::Common::I8> ("/OWN/INPUT/DYNAMIC/SUB", SubDataset);
    CreateDatasetInFile ();
}

void DynamicSummaryRepository::InitDataset ()
{
    MainlyRepositoryBase<MultiSummaryInfo<SG::DataStructure::FEM::DynamicType>>::InitDataset ();

    auto insertData = [=] () {
        // 触发持久化信号
        GetDatabase ().GetHDF5Hub ()->m_dynamicSummarySignal ();

        // 便利所有index表，进行数据的读取
        std::map<SG::DataStructure::Common::Id, std::set<SG::DataStructure::FEM::DynamicType>> infos;
        for (auto&& i : GetDatabase ().GetHDF5Hub()->m_dynamicTypeWithIndexPathMapping)
        {
            if (GetDatabase ().GetFile ()->exist (i.second))
            {
                std::vector<SG::DataStructure::Common::Id> idList;
                GetDataset (i.second).read (idList);
                for (auto&& id : idList)
                {
                    infos[id].insert (i.first);
                }
            }
        }

        for (const auto& pair : infos)
        {
            std::vector<SG::DataStructure::FEM::DynamicType>                     vec (pair.second.begin (), pair.second.end ());
            SG::DBManager::MultiSummaryInfo<SG::DataStructure::FEM::DynamicType> info (pair.first, vec);
            Add (info);
        }
    };

    if (GetMainDatasetInfo ().GetRowCount () == 0)
    {
        insertData ();
        SortData ();
    }
}
std::vector<SG::DBManager::MultiSummaryInfo<SG::DataStructure::FEM::DynamicType>> DynamicSummaryRepository::GetAllData ()
{
    throw std::runtime_error ("DynamicSummaryRepository::GetAllData donot suppose");
}
std::vector<SG::DataStructure::FEM::DynamicType> DynamicSummaryRepository::GetDynamicType (SG::DataStructure::Common::Id sid)
{
    MultiSummaryInfo<SG::DataStructure::FEM::DynamicType> loadInfo;  // NOLINT(misc-const-correctness)
    if (FindById (sid, loadInfo) == SG::DataStructure::Common::Status::STATUS_Success)
    {
        return loadInfo.m_type;
    }
    throw std::runtime_error ("DynamicSummaryRepository::GetDynamicType bad sid:" + std::to_string (sid));
    return { SG::DataStructure::FEM::DynamicType::DYNAMICTYPE_UnKonwn };
}

void DynamicSummaryRepository::DumpWriteCahce ()
{
    auto& writeStorage = this->GetMainCache ().m_writeStorage;

    // 1. flag设置为无顺序
    GetMainDatasetInfo ().SetIsSequential (false);

    // 主表数据
    std::vector<SummaryIDENTITY> IDENTITYData{};
    // 附表数据
    std::vector<SG::DataStructure::Common::I8> subData;

    // 2. 转换为nastran格式数据
    OwnToNastran (writeStorage, IDENTITYData, subData);

    // 3. 写出数据至文件
    WriteData (MainDataset, IDENTITYData);
    WriteData (SubDataset, subData);

    // 4. 更新Index表
    this->WriteIndexData (this->GetIndexDatasetInfo (), writeStorage);

    // 5. 清空缓存
    writeStorage.clear ();
}

std::vector<DynamicSummaryRepository::DataType>*  DynamicSummaryRepository::LoadReadCache (std::size_t loadIndex)
{
    // 1. 读取范围内主表数据
    std::vector<SummaryIDENTITY> IDENTITYData;
    LoadMainMetadata (loadIndex, IDENTITYData);

    if (IDENTITYData.empty ())
        return nullptr;

    // 2. 读取范围内附表数据
    std::vector<SG::DataStructure::Common::I8> subData;
    LoadSecondaryMetadata (IDENTITYData, m_beginIndex, m_length, SubDataset, subData);

    // 3. 将数据转换为自己的格式放入缓存
    auto* cacheVector = m_cacheHelper.LookupOrCreateVector<DataType> (GetMainCache ().m_readCacheKey, IDENTITYData.size ());
    NastranToOwn (IDENTITYData, subData, *cacheVector);
    return cacheVector;
}

void DynamicSummaryRepository::SortData ()
{
    if (this->GetMainCache ().m_writeStorage.size ())
    {
        DumpWriteCahce ();
    }
    if (!this->GetMainDatasetInfo ().IsCreate ())
    {
        return;
    }
    // 1. 读取主表数据
    std::vector<SummaryIDENTITY> IDENTITYData;
    GetDataset (MainDataset).read (IDENTITYData);

    if (IDENTITYData.empty ())
    {
        GetMainDatasetInfo ().SetIsSequential (true);
        return;
    }

    // 2. 读取附表数据
    std::vector<SG::DataStructure::Common::I8> subData;
    GetDataset (SubDataset).read (subData);

    // 3. 将所有数据转换
    std::vector<MultiSummaryInfo<SG::DataStructure::FEM::DynamicType>> AllData{};
    NastranToOwn (IDENTITYData, subData, AllData);

    // 4. 排序
    std::sort (AllData.begin (), AllData.end ());

    // 5. 转换回nastran格式
    OwnToNastran (AllData, IDENTITYData, subData, true);

    // 6. 写出主表数据至文件
    GetDataset (MainDataset).write (IDENTITYData);
    // 7. 写出附表数据至文件
    GetDataset (SubDataset).write (subData);

    // 8. 重写索引
    RewriteIndexData (AllData);

    // 9. 设置为已顺序
    GetMainDatasetInfo ().SetIsSequential (true);
}

void DynamicSummaryRepository::OwnToNastran (std::vector<SG::DBManager::MultiSummaryInfo<SG::DataStructure::FEM::DynamicType>>& own,
                                             std::vector<SG::DBManager::SummaryIDENTITY>& _OUT IDENTITYData,
                                             std::vector<SG::DataStructure::Common::I8>& _OUT  subData,
                                             bool                                              isSort)
{
    subData.clear ();
    IDENTITYData.clear ();
    IDENTITYData.reserve (own.size ());

    // 获取已有数据条数，主要是放在主表的POS字段
    // 如果是重新排序的时候，Pos都是从0 开始的
    size_t count = isSort ? 0 : this->GetDatasetInfo (SubDataset).GetRowCount ();

    // OwnIdent 代表咱们自己的数据结构
    // NasIdent 代表nastran的数据结构
    for (auto& OwnIdent : own)
    {
        // 写入附表
        subData.insert (subData.end (), OwnIdent.m_type.begin (), OwnIdent.m_type.end ());

        const size_t len = OwnIdent.m_type.size ();

        // 写入IDENTITY
        SG::DBManager::SummaryIDENTITY NasIdent{};
        NasIdent.m_sId        = OwnIdent.m_sId;
        NasIdent.m_beginIndex = static_cast<SG::DataStructure::Common::I64> (count);
        NasIdent.m_length     = static_cast<SG::DataStructure::Common::I64> (len);

        IDENTITYData.emplace_back (NasIdent);

        count += len;
    }
}

void DynamicSummaryRepository::NastranToOwn (std::vector<SG::DBManager::SummaryIDENTITY>& IDENTITYData,
                                             std::vector<SG::DataStructure::Common::I8>&  subData,
                                             std::vector<SG::DBManager::MultiSummaryInfo<SG::DataStructure::FEM::DynamicType>>& _OUT own)
{
    own.clear ();
    own.reserve (IDENTITYData.size ());

    // 代表初始的Index 位置, 因为数据有可能是截取了附表的一部分，所有主表中根据POS找的时候需要对应一下，
    // 比如第一个主表数据中POS字段为10000， 附表的vector的数据 就是从附表中的第10000个开始对应的 也就是Index==0的
    const SG::DataStructure::Common::I64 index = IDENTITYData[0].m_beginIndex;

    SG::DBManager::MultiSummaryInfo<SG::DataStructure::FEM::DynamicType> const tempown;
    own.resize (IDENTITYData.size (), tempown);

    for (size_t i = 0; i < IDENTITYData.size (); i++)
    {
        auto& OwnIdent = own[i];
        auto& NasIdent = IDENTITYData[i];

        OwnIdent.m_sId = NasIdent.m_sId;
        if (NasIdent.m_length != 0)
        {
            OwnIdent.m_type.reserve (NasIdent.m_length);
            auto beginIndex = NasIdent.m_beginIndex - index;
            for (auto i = 0; i < NasIdent.m_length; i++)
            {
                OwnIdent.m_type.push_back (static_cast<SG::DataStructure::FEM::DynamicType> (subData[beginIndex + i]));
            }
        }
    }
}
